package com.vzaar;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;

/**
 * Helper class for file formats <a href="http://vzaar.com">vzaar.com</a> 
 * can decode from.
 *  
 * Trusted formats are input formats that are well tested and safe to
 * use.  
 * 
 * Accepted formats includes the trusted formats as well as formats
 * that may work but are at your own risk to use.
 * 
 * @author Marc G. Smith
 */
public class AcceptedFileExtension 
{
	///////////////////////////////////////////////////////////////////////////
	// Private Static Members /////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////

	private final static Map<String, AcceptedFileExtension> TRUSTED =
		new TreeMap<String, AcceptedFileExtension>();

	private final static Map<String, AcceptedFileExtension> ACCEPTED =
		new TreeMap<String, AcceptedFileExtension>();
	
	static {
		TRUSTED.put("asf", new AcceptedFileExtension("asf", "asf format"));
		TRUSTED.put("avi", new AcceptedFileExtension("avi", "avi format"));
		TRUSTED.put("flv", new AcceptedFileExtension("flv", "flv video format"));
		TRUSTED.put("m4v", new AcceptedFileExtension("m4v", "raw MPEG4 video format"));
		TRUSTED.put("mov", new AcceptedFileExtension("mov", "QuickTime/MPEG4/Motion JPEG 2000 format"));
		TRUSTED.put("mp4", new AcceptedFileExtension("mp4", "QuickTime/MPEG4/Motion JPEG 2000 format"));
		TRUSTED.put("m4a", new AcceptedFileExtension("m4a", "QuickTime/MPEG4/Motion JPEG 2000 format"));
		TRUSTED.put("3gp", new AcceptedFileExtension("3gp", "QuickTime/MPEG4/Motion JPEG 2000 format"));
		TRUSTED.put("3g2", new AcceptedFileExtension("3g2", "QuickTime/MPEG4/Motion JPEG 2000 format"));
		TRUSTED.put("mj2", new AcceptedFileExtension("mj2", "QuickTime/MPEG4/Motion JPEG 2000 format"));
		TRUSTED.put("wmv", new AcceptedFileExtension("wmv", "Windows Media Video format"));
		
		ACCEPTED.putAll(TRUSTED);
		ACCEPTED.put("4xm", new AcceptedFileExtension("4xm", "4X Technologies format"));
		ACCEPTED.put("MTV", new AcceptedFileExtension("MTV", "MTV format"));
		ACCEPTED.put("RoQ", new AcceptedFileExtension("RoQ", "Id RoQ format"));
		ACCEPTED.put("aac", new AcceptedFileExtension("aac", "ADTS AAC"));
		ACCEPTED.put("ac3", new AcceptedFileExtension("ac3", "raw ac3"));
		ACCEPTED.put("aiff", new AcceptedFileExtension("aiff", "Audio IFF"));
		ACCEPTED.put("alaw", new AcceptedFileExtension("alaw", "pcm A law format"));
		ACCEPTED.put("amr", new AcceptedFileExtension("amr", "3gpp amr file format"));
		ACCEPTED.put("apc", new AcceptedFileExtension("apc", "CRYO APC format"));
		ACCEPTED.put("ape", new AcceptedFileExtension("ape", "Monkey's Audio"));
		ACCEPTED.put("au", new AcceptedFileExtension("au", "SUN AU Format"));
		ACCEPTED.put("avs", new AcceptedFileExtension("avs", "avs format"));
		ACCEPTED.put("bethsoftvid", new AcceptedFileExtension("bethsoftvid", "Bethesda Softworks 'Daggerfall' VID format"));
		ACCEPTED.put("bktr", new AcceptedFileExtension("bktr", "video grab"));
		ACCEPTED.put("c93", new AcceptedFileExtension("c93", "Interplay C93"));
		ACCEPTED.put("daud", new AcceptedFileExtension("daud", "D -Cinema audio format"));
		ACCEPTED.put("dsicin", new AcceptedFileExtension("dsicin", "Delphine Software International CIN format"));
		ACCEPTED.put("dts", new AcceptedFileExtension("dts", "raw dts"));
		ACCEPTED.put("dv", new AcceptedFileExtension("dv", "DV video format"));
		ACCEPTED.put("dxa", new AcceptedFileExtension("dxa", "dxa"));
		ACCEPTED.put("ea", new AcceptedFileExtension("ea", "Electronic Arts Multimedia Format"));
		ACCEPTED.put("ffm", new AcceptedFileExtension("ffm", "ffm format"));
		ACCEPTED.put("film_cpk", new AcceptedFileExtension("film_cpk", "Sega FILM/CPK format"));
		ACCEPTED.put("flac", new AcceptedFileExtension("flac", "raw flac"));
		ACCEPTED.put("flic", new AcceptedFileExtension("flic", "FLI/FLC/FLX animation format"));
		ACCEPTED.put("gif", new AcceptedFileExtension("gif", "GIF Animation"));
		ACCEPTED.put("gxf", new AcceptedFileExtension("gxf", "GXF format"));
		ACCEPTED.put("h261", new AcceptedFileExtension("h261", "raw h261"));
		ACCEPTED.put("h263", new AcceptedFileExtension("h263", "raw h263"));
		ACCEPTED.put("h264", new AcceptedFileExtension("h264", "raw H264 video format"));
		ACCEPTED.put("idcin", new AcceptedFileExtension("idcin", "Id CIN format"));
		ACCEPTED.put("image2", new AcceptedFileExtension("image2", "image2 sequence"));
		ACCEPTED.put("image2pipe", new AcceptedFileExtension("image2pipe", "piped image2 sequence"));
		ACCEPTED.put("ingenient", new AcceptedFileExtension("ingenient", "Ingenient MJPEG"));
		ACCEPTED.put("ipmovie", new AcceptedFileExtension("ipmovie", "Interplay MVE format"));
		ACCEPTED.put("matroska", new AcceptedFileExtension("matroska", "Matroska File Format"));
		ACCEPTED.put("mjpeg", new AcceptedFileExtension("mjpeg", "MJPEG video"));
		ACCEPTED.put("mm", new AcceptedFileExtension("mm", "American Laser Games MM format"));
		ACCEPTED.put("mmf", new AcceptedFileExtension("mmf", "mmf format"));
		ACCEPTED.put("mp3", new AcceptedFileExtension("mp3", "MPEG audio layer 3"));
		ACCEPTED.put("mpc", new AcceptedFileExtension("mpc", "musepack"));
		ACCEPTED.put("mpeg", new AcceptedFileExtension("mpeg", "MPEG1 System format"));
		ACCEPTED.put("mpegts", new AcceptedFileExtension("mpegts", "MPEG2 transport stream format"));
		ACCEPTED.put("mpegtsraw", new AcceptedFileExtension("mpegtsraw", "MPEG2 raw transport stream format"));
		ACCEPTED.put("mpegvideo", new AcceptedFileExtension("mpegvideo", "MPEG video"));
		ACCEPTED.put("mulaw", new AcceptedFileExtension("mulaw", "pcm mu law format"));
		ACCEPTED.put("mxf", new AcceptedFileExtension("mxf", "MXF format"));
		ACCEPTED.put("nsv", new AcceptedFileExtension("nsv", "NullSoft Video format"));
		ACCEPTED.put("nut", new AcceptedFileExtension("nut", "nut format"));
		ACCEPTED.put("nuv", new AcceptedFileExtension("nuv", "NuppelVideo format"));
		ACCEPTED.put("ogg", new AcceptedFileExtension("ogg", "Ogg format"));
		ACCEPTED.put("oss", new AcceptedFileExtension("oss", "audio grab and output"));
		ACCEPTED.put("psxstr", new AcceptedFileExtension("psxstr", "Sony Playstation STR format"));
		ACCEPTED.put("rawvideo", new AcceptedFileExtension("rawvideo", "raw video format"));
		ACCEPTED.put("redir", new AcceptedFileExtension("redir", "Redirector format"));
		ACCEPTED.put("rm", new AcceptedFileExtension("rm", "rm format"));
		ACCEPTED.put("rtsp", new AcceptedFileExtension("rtsp", "RTSP input format"));
		ACCEPTED.put("s16be", new AcceptedFileExtension("s16be", "pcm signed 16 bit big endian format"));
		ACCEPTED.put("s16le", new AcceptedFileExtension("s16le", "pcm signed 16 bit little endian format"));
		ACCEPTED.put("s8", new AcceptedFileExtension("s8", "pcm signed 8 bit format"));
		ACCEPTED.put("sdp", new AcceptedFileExtension("sdp", "SDP"));
		ACCEPTED.put("shn", new AcceptedFileExtension("shn", "raw shorten"));
		ACCEPTED.put("smk", new AcceptedFileExtension("smk", "Smacker Video"));
		ACCEPTED.put("sol", new AcceptedFileExtension("sol", "Sierra SOL Format"));
		ACCEPTED.put("swf", new AcceptedFileExtension("swf", "Flash format"));
		ACCEPTED.put("thp", new AcceptedFileExtension("thp", "THP"));
		ACCEPTED.put("tiertexseq", new AcceptedFileExtension("tiertexseq", "Tiertex Limited SEQ format"));
		ACCEPTED.put("tta", new AcceptedFileExtension("tta", "true -audio"));
		ACCEPTED.put("txd", new AcceptedFileExtension("txd", "txd format"));
		ACCEPTED.put("u16be", new AcceptedFileExtension("u16be", "pcm unsigned 16 bit big endian format"));
		ACCEPTED.put("u16le", new AcceptedFileExtension("u16le", "pcm unsigned 16 bit little endian format"));
		ACCEPTED.put("u8", new AcceptedFileExtension("u8", "pcm unsigned 8 bit format"));
		ACCEPTED.put("vc1", new AcceptedFileExtension("vc1", "raw vc1"));
		ACCEPTED.put("vmd", new AcceptedFileExtension("vmd", "Sierra VMD format"));
		ACCEPTED.put("voc", new AcceptedFileExtension("voc", "Creative Voice File format"));
		ACCEPTED.put("wav", new AcceptedFileExtension("wav", "wav format"));
		ACCEPTED.put("wc3movie", new AcceptedFileExtension("wc3movie", "Wing Commander III movie format"));
		ACCEPTED.put("wsaud", new AcceptedFileExtension("wsaud", "Westwood Studios audio format"));
		ACCEPTED.put("wsvqa", new AcceptedFileExtension("wsvqa", "Westwood Studios VQA format"));
		ACCEPTED.put("wv", new AcceptedFileExtension("wv", "WavPack"));
		ACCEPTED.put("yuv4mpegpipe", new AcceptedFileExtension("yuv4mpegpipe", "YUV4MPEG pipe format"));
	}

	///////////////////////////////////////////////////////////////////////////
	// Public Static Methods //////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////
	
	/**
	 * Provided with a file name or just the extension this method will 
	 * return true if the file format is a trusted format to be
	 * decoded by <a href="http://vzaar.com">vzaar.com</a>. 
	 * 
	 * @param fileNameOrExtension the full filename or just the extension
	 * @return true if a trusted and tested file format, false otherwise
	 */
	public static boolean isTrustedFormat(String fileNameOrExtension) {
		return TRUSTED.containsKey(
			normaliseFileExtension(fileNameOrExtension));
	}

	///////////////////////////////////////////////////////////////////////////

	/**
	 * Provided with a file name or just the extension this method will 
	 * return true if the file format is an accepted format. This includes
	 * trusted as well as untrusted formats. Untrusted formats are not
	 * well tested and are at your own risk. 
	 * 
	 * @param fileNameOrExtension the full filename or just the extension
	 * @return true if a accepted file format, false otherwise
	 */
	public static boolean isAcceptedFormat(String fileNameOrExtension) {
		return ACCEPTED.containsKey(
			normaliseFileExtension(fileNameOrExtension));
	}
	
	///////////////////////////////////////////////////////////////////////////
	
	/**
	 * Returns a list of the trusted file formats that have been tested
	 * for decoding by <a href="http://vzaar.com">vzaar.com</a>.
	 * 
	 * @return the list of trusted file extensions for formats. 
	 */
	public static Collection<AcceptedFileExtension> getTrustedFormats() {
		return Collections.unmodifiableCollection(TRUSTED.values());
	}

	///////////////////////////////////////////////////////////////////////////

	/**
	 * Returns a list of the accepted formats for decoding by 
	 * <a href="http://vzaar.com">vzaar.com</a>. Accepted formats include
	 * untested formats and are uploaded at your own risk. 
	 * 
	 * @return the list of accepted file extensions for formats. 
	 */
	public static Collection<AcceptedFileExtension> getAcceptedFormats() {
		return Collections.unmodifiableCollection(ACCEPTED.values());
	}

	///////////////////////////////////////////////////////////////////////////
	// Private Static Methods /////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////

	/**
	 * Normalise a filename or extension to enable lookup of extension maps.
	 * 
	 * @param fileNameOrExtension the full filename or just the extension
	 * @return the extension
	 */
	private static String normaliseFileExtension(String fileNameOrExtension) {
		int index = fileNameOrExtension.lastIndexOf(".");
		if(index > -1) {
			fileNameOrExtension = fileNameOrExtension.substring(index + 1);
		}
		return fileNameOrExtension.toLowerCase();
	}
	
	///////////////////////////////////////////////////////////////////////////
	// Private Members ////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////

	private String extension;
	private String description;
	
	///////////////////////////////////////////////////////////////////////////
	// Private Methods ////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////

	/**
	 * Private constructor.
	 * @param extension the extension as just the characters in lower case
	 * @param description the description of the file format
	 */
	private AcceptedFileExtension(String extension, String description) {
		this.extension = extension;
		this.description = description;
	}

	///////////////////////////////////////////////////////////////////////////
	// Public Methods /////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////

	/**
	 * The file extension.
	 * 
	 * @return the extension
	 */
	public String getExtension() {
		return extension;
	}

	///////////////////////////////////////////////////////////////////////////

	/**
	 * The file extension description
	 * 
	 * @return the description
	 */
	public String getDescription() {
		return description;
	}
	
	///////////////////////////////////////////////////////////////////////////
}
